﻿namespace RPCenter.WindowsAPI
{
    using Microsoft.VisualBasic.CompilerServices; 
    using System;
    using System.ComponentModel;
    using System.Diagnostics;

    public class NativeMemoryReader : IDisposable
    {
        private Process _TargetProcess = null;
        private IntPtr _TargetProcessHandle = IntPtr.Zero;
        private bool disposedValue;

        public NativeMemoryReader(Process ProcessToRead)
        {
            if (ProcessToRead == null)
            {
                throw new ArgumentNullException("ProcessToRead");
            }
            this._TargetProcess = ProcessToRead;
            this.Open();
        }

        public void Close()
        {
            if (this._TargetProcessHandle != IntPtr.Zero)
            {
                if (!ApiDefinitions.CloseHandle(this._TargetProcessHandle))
                {
                    throw new ApplicationException("Unable to close process handle. The last error reported was: " + new Win32Exception().Message);
                }
                this._TargetProcessHandle = IntPtr.Zero;
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue && (this._TargetProcessHandle != IntPtr.Zero))
            {
                try
                {
                    ApiDefinitions.CloseHandle(this._TargetProcessHandle);
                }
                catch (Exception exception1)
                {
                    ProjectData.SetProjectError(exception1);
                    Exception exception = exception1;
                    ProjectData.ClearProjectError();
                }
            }
            this.disposedValue = true;
        }

        //protected override void Finalize()
        //{
        //    this.Dispose(false);
        //    //base.Finalize();
        //}

        public void Open()
        {
            if (this._TargetProcess == null)
            {
                throw new ApplicationException("Process not found");
            }
            if (this._TargetProcessHandle != IntPtr.Zero)
            {
                throw new ApplicationException("A handle to the process has already been obtained, close the existing handle by calling the Close method before calling Open again");
            }
            this._TargetProcessHandle = ApiDefinitions.OpenProcess(0x410, true, (uint) this._TargetProcess.Id);
            if (this._TargetProcessHandle == IntPtr.Zero)
            {
                throw new ApplicationException("Unable to open process for memory reading. The last error reported was: " + new Win32Exception().Message);
            }
        }

        public byte[] ReadMemory(IntPtr MemoryAddress, int Count)
        {
            if (this._TargetProcessHandle == IntPtr.Zero)
            {
                this.Open();
            }
            byte[] lpBuffer = new byte[Count + 1];
            uint lpNumberOfBytesRead = 0;
            if (ApiDefinitions.ReadProcessMemory(this._TargetProcessHandle, MemoryAddress, lpBuffer, (uint) Count, out lpNumberOfBytesRead))
            {
                return lpBuffer;
            }
            return null;
        }

        public Process TargetProcess
        {
            get
            {
                return this._TargetProcess;
            }
        }

        public IntPtr TargetProcessHandle
        {
            get
            {
                return this._TargetProcessHandle;
            }
        }
    }
}

